package com.fsserver.common.utils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 订单号生成工具类
 * 生成不同业务类型的订单号，保证唯一性和可读性
 * 
 * @author fsserver
 * @date 2025-03-13
 */
public class OrderNoGenerator {
    
    // 日期格式化器 - 年月日时分秒毫秒
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
    
    // 日期格式化器 - 年月日
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    
    // 计数器，用于同一毫秒内生成不同的序列号
    private static final AtomicInteger SEQUENCE = new AtomicInteger(1);
    
    // 计数器最大值
    private static final int MAX_SEQUENCE = 9999;
    
    // 雪花算法ID生成器
    private static SnowflakeIdGenerator snowflakeIdGenerator;
    
    // 是否启用分布式ID生成
    private static boolean enableDistributed = false;
    
    // 业务类型前缀
    public static final String PREFIX_PAYMENT_ORDER = "PO"; // 支付订单
    public static final String PREFIX_PAYMENT_TRANSACTION = "PT"; // 支付交易
    public static final String PREFIX_REFUND = "RF"; // 退款
    public static final String PREFIX_RECONCILIATION = "RC"; // 对账
    public static final String PREFIX_NOTIFICATION = "NT"; // 通知
    
    // 支付类型代码 (两位数字)
    public static final String PAY_TYPE_ALIPAY = "01";
    public static final String PAY_TYPE_WECHAT = "02";
    public static final String PAY_TYPE_UNIONPAY = "03";
    public static final String PAY_TYPE_PAYPAL = "04";
    public static final String PAY_TYPE_OTHER = "99";
    
    /**
     * 初始化雪花算法ID生成器
     * 
     * @param dataCenterId 数据中心ID
     * @param workerId 工作节点ID
     * @param enableDistributed 是否启用分布式ID生成
     */
    public static void initSnowflake(long dataCenterId, long workerId, boolean enableDistributed) {
        snowflakeIdGenerator = new SnowflakeIdGenerator(workerId, dataCenterId);
        OrderNoGenerator.enableDistributed = enableDistributed;
    }
    
    /**
     * 生成支付订单号
     * 格式: PO + 支付类型(2位) + 日期时间(17位) + 随机数(4位) = 25位
     * 例如: PO01202503131415162345678
     * 
     * @param paymentType 支付类型
     * @return 支付订单号
     */
    public static String generatePaymentOrderNo(String paymentType) {
        return generateOrderNo(PREFIX_PAYMENT_ORDER, getPaymentTypeCode(paymentType));
    }
    
    /**
     * 生成支付交易号
     * 格式: PT + 支付类型(2位) + 日期时间(17位) + 随机数(4位) = 25位
     * 例如: PT01202503131415162345678
     * 
     * @param paymentType 支付类型
     * @return 支付交易号
     */
    public static String generatePaymentTransactionNo(String paymentType) {
        return generateOrderNo(PREFIX_PAYMENT_TRANSACTION, getPaymentTypeCode(paymentType));
    }
    
    /**
     * 生成退款号
     * 格式: RF + 支付类型(2位) + 日期时间(17位) + 随机数(4位) = 25位
     * 例如: RF01202503131415162345678
     * 
     * @param paymentType 支付类型
     * @return 退款号
     */
    public static String generateRefundNo(String paymentType) {
        return generateOrderNo(PREFIX_REFUND, getPaymentTypeCode(paymentType));
    }
    
    /**
     * 生成对账号
     * 格式: RC + 支付类型(2位) + 日期(8位) + 随机数(4位) = 16位
     * 例如: RC0120250313XXXX
     * 
     * @param paymentType 支付类型
     * @return 对账号
     */
    public static String generateReconciliationNo(String paymentType) {
        StringBuilder sb = new StringBuilder(16);
        sb.append(PREFIX_RECONCILIATION);
        sb.append(getPaymentTypeCode(paymentType));
        
        // 添加日期部分 (8位)
        sb.append(LocalDateTime.now().format(DATE_FORMATTER));
        
        // 添加4位随机数或分布式ID
        if (enableDistributed && snowflakeIdGenerator != null) {
            // 使用雪花算法生成ID的后4位
            String snowflakeId = String.valueOf(snowflakeIdGenerator.nextId());
            sb.append(snowflakeId.substring(snowflakeId.length() - 4));
        } else {
            // 使用随机数
            sb.append(String.format("%04d", ThreadLocalRandom.current().nextInt(10000)));
        }
        
        return sb.toString();
    }
    
    /**
     * 生成通知编号
     * 格式: NT + 通知类型(2位) + 日期时间(17位) + 随机数(4位) = 25位
     * 例如: NT01202503131415162345678
     * 
     * @param notificationType 通知类型 (01:支付通知, 02:退款通知, 03:对账通知)
     * @return 通知编号
     */
    public static String generateNotificationNo(String notificationType) {
        String typeCode = "99"; // 默认其他类型
        
        if ("PAYMENT".equals(notificationType)) {
            typeCode = "01";
        } else if ("REFUND".equals(notificationType)) {
            typeCode = "02";
        } else if ("RECONCILIATION".equals(notificationType)) {
            typeCode = "03";
        }
        
        return generateOrderNo(PREFIX_NOTIFICATION, typeCode);
    }
    
    /**
     * 生成通用订单号
     * 
     * @param prefix 业务前缀
     * @param typeCode 类型代码
     * @return 订单号
     */
    private static String generateOrderNo(String prefix, String typeCode) {
        StringBuilder sb = new StringBuilder(25);
        sb.append(prefix);
        sb.append(typeCode);
        
        // 添加时间戳部分 (17位)
        sb.append(LocalDateTime.now().format(DATE_TIME_FORMATTER));
        
        // 添加序列号部分 (4位)
        if (enableDistributed && snowflakeIdGenerator != null) {
            // 使用雪花算法生成ID的后4位
            String snowflakeId = String.valueOf(snowflakeIdGenerator.nextId());
            sb.append(snowflakeId.substring(snowflakeId.length() - 4));
        } else {
            // 使用本地序列号
            int sequence = getNextSequence();
            sb.append(String.format("%04d", sequence));
        }
        
        return sb.toString();
    }
    
    /**
     * 获取支付类型代码
     * 
     * @param paymentType 支付类型
     * @return 支付类型代码
     */
    private static String getPaymentTypeCode(String paymentType) {
        if (paymentType == null) {
            return PAY_TYPE_OTHER;
        }
        
        switch (paymentType.toUpperCase()) {
            case "ALIPAY":
                return PAY_TYPE_ALIPAY;
            case "WECHAT":
                return PAY_TYPE_WECHAT;
            case "UNIONPAY":
                return PAY_TYPE_UNIONPAY;
            case "PAYPAL":
                return PAY_TYPE_PAYPAL;
            default:
                return PAY_TYPE_OTHER;
        }
    }
    
    /**
     * 获取下一个序列号
     * 
     * @return 序列号
     */
    private static int getNextSequence() {
        int current = SEQUENCE.getAndIncrement();
        if (current > MAX_SEQUENCE) {
            // 超过最大值，重置为1
            SEQUENCE.set(1);
            return 1;
        }
        return current;
    }
    
    /**
     * 从订单号中提取业务类型
     * 
     * @param orderNo 订单号
     * @return 业务类型
     */
    public static String extractBusinessType(String orderNo) {
        if (orderNo == null || orderNo.length() < 2) {
            return "UNKNOWN";
        }
        
        String prefix = orderNo.substring(0, 2);
        switch (prefix) {
            case PREFIX_PAYMENT_ORDER:
                return "PAYMENT_ORDER";
            case PREFIX_PAYMENT_TRANSACTION:
                return "PAYMENT_TRANSACTION";
            case PREFIX_REFUND:
                return "REFUND";
            case PREFIX_RECONCILIATION:
                return "RECONCILIATION";
            case PREFIX_NOTIFICATION:
                return "NOTIFICATION";
            default:
                return "UNKNOWN";
        }
    }
    
    /**
     * 从订单号中提取支付类型
     * 
     * @param orderNo 订单号
     * @return 支付类型
     */
    public static String extractPaymentType(String orderNo) {
        if (orderNo == null || orderNo.length() < 4) {
            return "UNKNOWN";
        }
        
        String typeCode = orderNo.substring(2, 4);
        switch (typeCode) {
            case PAY_TYPE_ALIPAY:
                return "ALIPAY";
            case PAY_TYPE_WECHAT:
                return "WECHAT";
            case PAY_TYPE_UNIONPAY:
                return "UNIONPAY";
            case PAY_TYPE_PAYPAL:
                return "PAYPAL";
            default:
                return "OTHER";
        }
    }
    
    /**
     * 从订单号中提取创建日期
     * 
     * @param orderNo 订单号
     * @return 创建日期字符串 (yyyyMMdd)
     */
    public static String extractCreateDate(String orderNo) {
        if (orderNo == null || orderNo.length() < 12) {
            return "";
        }
        
        return orderNo.substring(4, 12);
    }
} 